using System;
using System.Collections.Generic;
using System.Text;
using JustePort;

namespace axStream
{
    class Player
    {
        public class ErrorEventArgs : EventArgs
        {
            public enum ERRORNUMBER
            {
                ERRORCONNECTING = 0,
                ERRORRECORDING = 1,
                ERRORSENDING = 2
            }
            public ERRORNUMBER Error;
            public Exception Exception;
        }

        private IDisposable m_Recorder;
        private byte[] m_RecBuffer;
        private RAOPClient at;
        private string ip;
        private double Volume = -144;

        public delegate void OnConnectEventHandler(object sender, EventArgs e);
        public event OnConnectEventHandler OnConnect;
        public delegate void OnDisconnectEventHandler(object sender, EventArgs e);
        public event OnDisconnectEventHandler OnDisconnect;
        public delegate void OnErrorEventHandler(object sender, ErrorEventArgs e);
        public event OnErrorEventHandler OnError;

        public Player(string ip, double volume)
        {
            this.Volume = volume;
            this.ip = ip;
        }

        protected virtual void ConnectedEvent(EventArgs e)
        {
            if (OnConnect != null)
                OnConnect(this, e);
        }

        protected virtual void DisconnectedEvent(EventArgs e)
        {
            if (OnDisconnect != null)
                OnDisconnect(this, e);
        }

        protected virtual void ErrorEvent(ErrorEventArgs e)
        {
            if (OnError != null)
                OnError(this, e);
        }

        private void DataArrived(IntPtr data, int size)
        {

            if (m_RecBuffer == null || m_RecBuffer.Length < size)
                m_RecBuffer = new byte[size];
            System.Runtime.InteropServices.Marshal.Copy(data, m_RecBuffer, 0, size);

            DataArrived(m_RecBuffer);
        }

        private void DataArrived(byte[] buf)
        {
            byte[] alac = BitBuffer.EncodeALAC(buf);

            try
            {
                at.SendSample(alac);
            }
            catch (Exception ex)
            {
                ErrorEventArgs e = new ErrorEventArgs();
                e.Error = ErrorEventArgs.ERRORNUMBER.ERRORSENDING;
                e.Exception = ex;
                ErrorEvent(e);

                Stop();
            }
        }

        public void SetVolume(double volume)
        {
            at.Volume = volume;
        }

        public void Stop()
        {
            if (m_Recorder != null)
                try
                {
                    m_Recorder.Dispose();
                }
                finally
                {
                    m_Recorder = null;
                }

            if (at != null)
            {
                try
                {
                    at.Disconnect();
                }
                finally
                {
                    at = null;
                }

                DisconnectedEvent(EventArgs.Empty);
            }
        }

        public void Start()
        {
            Stop();
            try
            {
                // Start Connection to Airport Express
                at = new RAOPClient(ip);
                at.Volume = Volume;

                try
                {
                    at.Connect();
                }
                catch (Exception ex)
                {
                    at = null;

                    ErrorEventArgs e = new ErrorEventArgs();
                    e.Error = ErrorEventArgs.ERRORNUMBER.ERRORCONNECTING;
                    e.Exception = ex;
                    ErrorEvent(e);

                    return;
                }

                string s = String.Format("JackStatus: {0}{1}JackType: {2}{3}",
                    at.JackStatus == RAOPClient.JACK_STATUS_CONNECTED ?
                    "connected" : "disconnected", Environment.NewLine,
                    at.JackType == RAOPClient.JACK_TYPE_DIGITAL ?
                    "digital" : "analog", Environment.NewLine);

                // Start recorder

                //m_Recorder = new WaveLib.WaveInRecorder(-1, new WaveLib.WaveFormat(44100, 16, 2), BitBuffer.FrameSize, 3, new WaveLib.BufferDoneEventHandler(DataArrived));

                m_Recorder = new SoundCapture.DirectSoundCapture(BitBuffer.FrameSize, 44100, 16, 2, DataArrived, true);
                

                ConnectedEvent(EventArgs.Empty);
            }
            catch (Exception ex)
            {
                ErrorEventArgs e = new ErrorEventArgs();
                e.Error = ErrorEventArgs.ERRORNUMBER.ERRORRECORDING;
                e.Exception = ex;
                ErrorEvent(e);

                at = null;
                Stop();
                //throw;
            }
        }

    }
}
